// Copyright (C) Calum Grant 2008

/// A macro to iterate all members of a container.
/** \ingroup  syntax */
#define foreach(v, container) \
	for(::dynamic::var v, v##_enumerator=var(container).enumerator(); \
		v##_enumerator && (v=*v##_enumerator,true); \
		++v##_enumerator)


/// The namespace for the C++Script library.
namespace dynamic
{
	/// The null value, same as var().
	/** \ingroup  lib */
	const var null;

	/// Access the global object (for global variables)
	/** \ingroup  lib */
	DYNAMIC_API var global();

	/// Retrieves the version-string of the library.
	/** \ingroup  lib */
	DYNAMIC_API var version();

	/// Retrieves a list of the current stack, as a list of strings.
	/** \ingroup exceptions */
	DYNAMIC_API var stack_trace();

	namespace internal
	{
		DYNAMIC_API var create_closure(const var & object, const char * method, const var & fn);
		template<typename Fn> DYNAMIC_API var function(Fn);
		DYNAMIC_API var named_functor(const var & fn, const char * name);
		DYNAMIC_API var bind(int args);	
		DYNAMIC_API var create_string(const char*);
		DYNAMIC_API var create_string(const std::string & str);
		DYNAMIC_API var create_string(const wchar_t*);
		DYNAMIC_API var create_string(const wstring & str);
		DYNAMIC_API string to_string(const var & v);
		DYNAMIC_API wstring to_wstring(const var & v);
		DYNAMIC_API bool register_function(const char * name, void * address);
		DYNAMIC_API void * lookup_function(const char * name);
		DYNAMIC_API const char * lookup_function(void * address);
		DYNAMIC_API var proxy(const var & v);
		DYNAMIC_API var proxy(const var & v, apartment * prev);
	}

	/// Takes a functor (fn) and returns a functor taking fewer arguments.
	/** \ingroup  lib */
	DYNAMIC_API var bind(const var & fn, const var & arg);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8);
	DYNAMIC_API var bind(const var & fn, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8, const var & a9);

	/// Creates an empty object (a container mapping strings to values).
	/** \ingroup  lib */
	DYNAMIC_API var object();

	/// Creates an empty object with a specified name.
	/** \ingroup  lib */
	DYNAMIC_API var object(const char * class_name);

	/// Creates a string with elements from another container.
	/** \ingroup  lib */
	DYNAMIC_API var string_from(const var & container);

	/// Creates a string with elements assigned from the iterators.
	/** \ingroup  lib */
	template<typename FwdIterator>
	var string_it(FwdIterator from, FwdIterator to)
	{
		var result = "";
		for(FwdIterator i=from; i!=to; ++i) result.push_back(*i);
		return result;
	}

	/// Converts most vars to a string.
	/** \ingroup  lib */
	DYNAMIC_API std::string pickle(const var &);

	/// Converts a string from pickle() back into a var.
	/** \ingroup  lib */
	DYNAMIC_API var unpickle(const std::string&);

	/// Removes the first element of a container.
	/** \ingroup  lib */
	DYNAMIC_API var tail(const var & container);

	/// Creates an empty map.
	/** \ingroup  lib */
	DYNAMIC_API var map();

	/// Creates a map with one key-value pair.
	/** \ingroup  lib */
	DYNAMIC_API var map(const var & key, const var & value);

	/// Creates an empty set.
	/** \ingroup  lib */
	DYNAMIC_API var set();

	/// Creates a set with one element.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var set(const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates a set with elements populated from another container.
	/** \ingroup  lib */
	DYNAMIC_API var set_from(const var & container);

	/// Creates a set with elements populated from the two iterators.
	/** \ingroup  lib */
	template<typename FwdIterator>
	var set_it(FwdIterator start, FwdIterator end)
	{
		var r = set();
		for(FwdIterator i=start; i!=end; ++i) r.insert(*i);
		return r;
	}

	/// Creates an array of given size containing the same item.
	/** \ingroup  lib */
	DYNAMIC_API var fill_array(const var & size, const var & item);

	/// Creates an empty array.
	/** \ingroup  lib */
	DYNAMIC_API var array();

	/// Creates an array with a single element.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &);	

	/// Creates an array with two elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&);

	/// Creates an array with three elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates an array with given elements.
	/** \ingroup  lib */
	DYNAMIC_API var array(const var &, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&, const var&);

	/// Creates an array with elements from another container.
	/** \ingroup  lib */
	DYNAMIC_API var array_from(const var &);

	/// Creates an array with elements between the iterators.
	/** \ingroup  lib */
	template<typename It>
	var array_it(It a, It b)
	{
		var l = array();
		l.impl().reserve(std::distance(a,b));
		for(It i=a; i!=b; ++i)
			l.push_back(*i);
		return l;
	}

	/// Creates an array from a C-style array.
	/** \ingroup  lib */
	template<std::size_t N>
	var array(var (&l)[N])
	{
		var a = array();
		a.impl().reserve(N);
		for(std::size_t i=0; i<N; ++i) a.push_back(l[i]);
		return a;
	}

	/// Creates an empty list.
	/** \ingroup  lib */
	DYNAMIC_API var list();

	/// Creates a list of given size containing the specified item.
	/** \ingroup  lib */
	DYNAMIC_API var fill_list(const var & size, const var & item);

	/// Creates a list from elements between a pair of iterators.
	/** \ingroup  lib */
	template<typename It>
	var list_it(It a, It b)
	{
		var l = list();
		for(It i=a; i!=b; ++i)
			l.push_back(*i);
		return l;
	}

	/// Creates a list containing a single item.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var & item);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing given items.
	/** \ingroup  lib */
	DYNAMIC_API var list(const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &, const var &);

	/// Creates a list containing elements from a given container.
	/** \ingroup  lib */
	DYNAMIC_API var list_from(const var & container);

	/// Creates a list with elements from a C-style array.
	/** \ingroup  lib */
	template<std::size_t N>
	var list(var (&ca)[N])
	{
		var l = list();
		for(std::size_t i=0; i<N; ++i) l.push_back(ca[i]);
		return l;
	}

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var range(const var & from, const var & to);

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var range(const var & from, const var & to, const var & step);

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var range_ex(const var & from, const var & to);

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var range_ex(const var & from, const var & to, const var & step);

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var sequence(const var & start, const var & len);

	/// Creates sequences.
	/** \ingroup  lib */
	DYNAMIC_API var sequence(const var & start, const var & len, const var & step);

	/// Creates a container with its elements reversed.
	/** \ingroup  lib */
	DYNAMIC_API var reverse(const var &);

	/// Creates a container which filters the contents of another container using a predicate.
	/** \ingroup  lib */
	DYNAMIC_API var filter(const var & container, const var & pred);

	/// Creates a container which transforms the elements of another container.
	/** \ingroup  lib */
	DYNAMIC_API var transform(const var & container, const var & fn);

	/// Creates a dispatcher object.
	/** \ingroup  lib */
	DYNAMIC_API var dispatcher(const var & object);

	/// Returns the larger of a or b.
	/** \ingroup  lib */
	DYNAMIC_API var max(const var &a, const var & b);

	/// Returns the smaller of a or b.
	/** \ingroup  lib */
	DYNAMIC_API var min(const var &a, const var & b);

	/// Opens the file and returns a file object.
	/** \ingroup  lib */
	DYNAMIC_API var open_file(const var & filename, std::ios_base::openmode flags);

	/// Opens a file for write.
	/** \ingroup  lib */
	DYNAMIC_API var write_file(const var & filename);

	/// Opens a file for reading.
	/** \ingroup  lib */
	DYNAMIC_API var read_file(const var & filename);

	/// Returns status information about a file.
	/** \ingroup  lib */
	DYNAMIC_API var fstat(const var & filename);

	/// Returns the file for standard input.
	/** \ingroup  lib */
	DYNAMIC_API var in();

	/// Returns the file for standard output.
	/** \ingroup  lib */
	DYNAMIC_API var out();

	/// Returns the file for standard errors.
	/** \ingroup  lib */
	DYNAMIC_API var err();

	/// Creates an in-memory file.
	/** \ingroup  lib */
	DYNAMIC_API var mem_file();

	/// Enumerates through all characters in a file.
	/** \ingroup  lib */
	DYNAMIC_API var characters(const var & file);

	/// Enumerates through all lines in a file.
	/** \ingroup  lib */
	DYNAMIC_API var lines(const var & file);

	/// Enumerates any function until it returns null.
	/** \ingroup  lib */
	DYNAMIC_API var enumerate(const var & fn);

	/// Writes a string to standard output.
	/** \ingroup  lib */
	DYNAMIC_API void write(const var &);

	/// Writes a string to standard output, followed by new line.
	/** \ingroup  lib */
	DYNAMIC_API void writeln(const var&);

	/// Writes a new line to standard output.
	/** \ingroup  lib */
	DYNAMIC_API void writeln();

	/// Reads a new line from standard input.
	/** \ingroup  lib */
	DYNAMIC_API var readln();

	/// Reads an entire file into a single string.
	/** \ingroup  lib */
	DYNAMIC_API var read_file(const var & file);

	/// Pickles an object into a file.
	/** \ingroup  lib */
	DYNAMIC_API void pickle_file(const var & name, const var & object);

	/// Reads an object file a file.
	/** \ingroup  lib */
	DYNAMIC_API var unpickle_file(const var & name);

	/// Pauses the current thread for the given interval.
	/** \ingroup  lib */
	DYNAMIC_API void sleep(const var & seconds);

	/// Executes a system call.
	/** \ingroup  lib */
	DYNAMIC_API var system(const var&);

	/// Creates a thread, and executes the given functor in the thread.
	/** \ingroup  lib */
	DYNAMIC_API var thread(const var & thread_fn);

	/// Executes the given functor in a globally-shared apartment.
	/** \ingroup  lib */
	DYNAMIC_API var global(const var & fn);

	/// Executes the given functor in a new apartment.
	/** \ingroup  lib */
	DYNAMIC_API var shared(const var & fn);

	/// Creates a event object.
	/** \ingroup  lib */
	DYNAMIC_API var event();

	/// Creates a mutex object.
	/** \ingroup  lib */
	DYNAMIC_API var mutex();

	/// Executes the given command (does not return).
	/** \ingroup  lib */
	DYNAMIC_API var exec(const var & file, const var & args);

	/// Creates a queue object.
	/** \ingroup  lib */
	DYNAMIC_API var queue();

	/// Creates a message queue object, with a given consumer functor running in the specified number of threads.
	/** \ingroup  lib */
	DYNAMIC_API var message_queue(const var & consumer, const var & threads=1);

	/// Returns a substring of a string
	/** \ingroup  lib */
	DYNAMIC_API var substring(const var & str, const var & range);

	/// Splits the string and returns an array of strings matching the predicate.
	/** \ingroup  lib */
	DYNAMIC_API var split_chars(var predicate, var str);

	/// Returns the range of the first occurrence of a particular string, or null.
	/** \ingroup  lib */
	DYNAMIC_API var string_find(const var & str, const var & needle);

	/// Returns the range of the last occurrance of a particular string, or null.
	/** \ingroup  lib */
	DYNAMIC_API var string_find_last(const var & str, const var & needle);

	/// Returns an array of ranges.
	/** \ingroup  lib */
	DYNAMIC_API var string_find_all(const var & str, const var & needle);

	/// Returns a string of a fixed size by truncating it or padding it with spaces.
	/** \ingroup  lib */
	DYNAMIC_API var pad(const var & str, const var & size);

	/// Returns true if ch is a space.
	/** \ingroup  lib */
	DYNAMIC_API var is_space(var ch);	// Could do more of these...

	/// Returns true if ch appears in str.
	/** \ingroup  lib */
	DYNAMIC_API var is_one_of(var str, var ch);

	/// Returns false if ch appears in str.
	/** \ingroup  lib */
	DYNAMIC_API var is_not_one_of(var str, var ch);

	/// Negates the given predicate.
	/** \ingroup  lib */
	DYNAMIC_API var is_not(var predicate, var value);

	/// Returns a functor taking a variable number of arguments.
	/** \ingroup  lib */
	DYNAMIC_API var varargs(const var & fn);

	/// Executes the given functor at the end of the block.
	/** \ingroup exceptions 
		\todo There is a bug in some compilers where the name isn't
		expanded out properly, meaning that you can't put two
		of these in the same block.*/
#define finally(F) ::dynamic::scopeguard guard##__COUNTER__(F);

	/// Executes a given functor when the scopeguard is destroyed.
	/** \ingroup exceptions */
	class DYNAMIC_API scopeguard : cg::not_copyable, cg::not_assignable
	{
		/// The functor to execute in the destructor.
		var m_on_exit;
	public:
		/// Pass in the functor to execute at scope exit.
		scopeguard(const var & v);

		/// Call the functor.
		~scopeguard();

		/// Do not call the functor in the destructor.
		void dismiss();

		/// Change the functor called in the destructor.
		void set(const var &);
	};

	/** \ingroup  lib */
#define enable_pickle(F) static bool script_register_##F = ::dynamic::internal::register_function(#F, (void*)&F);

	/// Temporarily disable the GC (can be nested).
	/** \ingroup  mem */
	DYNAMIC_API void gc_enable();	

	/// Reenable the GC.
	/** \ingroup  mem */
	DYNAMIC_API void gc_disable();

	/// Advise to perform a collection now (may not do anything) - put this into an idle loop.
	/** \ingroup  mem */
	DYNAMIC_API void gc_hint_collect();	

	/// Perform a collection now (inadvisible).
	/** \ingroup  mem */
	DYNAMIC_API void gc_force_collect();	

	/// Wait until the heap has grown by a factor of 3 before automatically performing a GC.
	/** Wait until the heap has grown by a factor of 2 before gc_collect() actually collects garbage
		At least 1000 collectible objects must be allocated before collect_garbage() does anything. */
	/** \ingroup  mem */
	DYNAMIC_API void gc_tune( int heap_factor=30, int idle_factor=20, int min_objects=1000 );

	/// Throws an exception if v is false.
	/** \ingroup exceptions */
	DYNAMIC_API void assertx(const var & v);

	/// Executes all tests in the map tests.
	/** \ingroup  lib */
	DYNAMIC_API var run_tests(const var & tests);

	/// Returns the time in seconds since the start of the program.
	/** \ingroup  lib */
	DYNAMIC_API double timer();

	/// Creates a var containing a specified var_impl.
	template<typename T>
	var create_impl(const T & t)
	{
		return var(t, var::assign_impl());
	}
}
